package com.ht.web_vr_home_tour_backend.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.web_vr_home_tour_backend.config.data.RedisConstants;
import com.ht.web_vr_home_tour_backend.dao.PojInfoDao;
import com.ht.web_vr_home_tour_backend.obj.dto.PojInfoDto;
import com.ht.web_vr_home_tour_backend.obj.dto.UserInfoDto;
import com.ht.web_vr_home_tour_backend.obj.enums.PojType;
import com.ht.web_vr_home_tour_backend.obj.enums.UserLevel;
import com.ht.web_vr_home_tour_backend.obj.pojo.ObjInfo;
import com.ht.web_vr_home_tour_backend.obj.pojo.PojInfo;
import com.ht.web_vr_home_tour_backend.obj.pojo.PojRefObj;
import com.ht.web_vr_home_tour_backend.utils.CacheClient;
import com.ht.web_vr_home_tour_backend.utils.RedisIdWorker;
import com.ht.web_vr_home_tour_backend.utils.ThreadLocalUtil;
import com.ht.web_vr_home_tour_backend.utils.exceptions.MessageException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 项目数据服务
 */
@Service
public class PojInfoService extends ServiceImpl<PojInfoDao, PojInfo> {
    private final CacheClient cacheClient;
    private final RedisIdWorker redisIdWorker;
    private final ObjInfoService objInfoService;
    private final PojRefObjService pojRefObjService;

    public PojInfoService(CacheClient cacheClient, RedisIdWorker redisIdWorker, ObjInfoService objInfoService, PojRefObjService pojRefObjService) {
        this.cacheClient = cacheClient;
        this.redisIdWorker = redisIdWorker;
        this.objInfoService = objInfoService;
        this.pojRefObjService = pojRefObjService;
    }

    /**
     * 根据id获取项目数据
     * @param id 项目数据id
     * @return 查询到的项目数据
     */
    public PojInfoDto getInfoById(String id) {
        PojInfo pojInfo = cacheClient.queryWithMutex(
                PojInfo.class,
                RedisConstants.tb_PojInfo_Id_keyPrefix,
                id,
                (_id) -> this.getById(Long.parseLong(_id)),
                RedisConstants.tb_Cache_Base_TTL
        );
        List<PojRefObj> refObjList = pojRefObjService.getAllRefObj(pojInfo.getId());
        List<ObjInfo> objInfoList = refObjList.stream()
                .map(val -> objInfoService.getObjInfoById(val.getObjId()))
                .collect(Collectors.toList());
        return new PojInfoDto(pojInfo, objInfoList);
    }

    /**
     * 保存项目数据
     * @param newPojInfo 新项目数据
     */
    @Transactional
    public long savePojInfo(PojInfo newPojInfo) {
        UserInfoDto userInfoDto = ThreadLocalUtil.getUserInfoDto();
        if (userInfoDto.getLevel() != UserLevel.Admin && !userInfoDto.getId().equals(newPojInfo.getCreateUser().toString())) {
            throw new MessageException("权限不足，无法操作");
        }

        newPojInfo.setCreateTime(null);
        newPojInfo.setCreateUser(null);
        if (newPojInfo.getId() == null) {
            long id = redisIdWorker.nextId(RedisConstants.icr_PojInfo_keyPrefix);
            newPojInfo.setId(id);
            this.save(newPojInfo);
            return id;
        } else {
            this.updateById(newPojInfo);
            return newPojInfo.getId();
        }
    }

    /**
     * 根据id更新项目
     * @param newPojInfo 新项目数据
     */
    @Transactional
    public void updatePojInfoById(PojInfo newPojInfo) {
        newPojInfo.setCreateTime(null);
        newPojInfo.setCreateUser(null);
        if (this.updateById(newPojInfo)) {
            cacheClient.dropCache(
                    RedisConstants.tb_PojInfo_Id_keyPrefix,
                    newPojInfo.getId().toString()
            );
        } else {
            throw new MessageException("保存失败，请重试");
        }
    }

    /**
     * 根据id删除项目
     * @param id 项目id
     */
    @Transactional
    public void deletePojInfoById(String id) {
        UserInfoDto userInfoDto = ThreadLocalUtil.getUserInfoDto();
        if (userInfoDto == null) {
            throw new RuntimeException("读取用户信息失败");
        }
        PojInfo pojInfo = this.getById(id);
        if (userInfoDto.getLevel() == UserLevel.Admin ||
                pojInfo.getCreateUser().toString().equals(userInfoDto.getId())) {
            if (this.removeById(id)) {
                cacheClient.dropCache(
                        RedisConstants.tb_PojInfo_Id_keyPrefix,
                        id
                );
            } else {
                throw new MessageException("删除失败，请重试");
            }
        } else {
            throw new MessageException("删除失败，权限不足");
        }
    }

    /**
     * 分页查询项目数据
     * @param current 当前页
     * @param size 分页大小
     * @param type 查询类型
     * @return 查询结果
     */
    public Page<PojInfoDto> pagePojInfoDto(long current, long size, PojType type) {
        Page<PojInfo> page = new Page<>(current, size);
        LambdaQueryChainWrapper<PojInfo> query = this.lambdaQuery();
        if (type != null) {
            query = query.eq(PojInfo::getPojType, type);
        }
        this.page(page, query.getWrapper());

        Page<PojInfoDto> dtoPage = new Page<>();
        BeanUtil.copyProperties(page, dtoPage);
        dtoPage.setRecords(
                page.getRecords()
                        .stream()
                        .map(item -> {
                            List<PojRefObj> refObjList = pojRefObjService.getAllRefObj(item.getId());
                            List<ObjInfo> objInfoList = refObjList.stream()
                                    .map(val -> objInfoService.getObjInfoById(val.getObjId()))
                                    .collect(Collectors.toList());
                            return new PojInfoDto(item, objInfoList);
                        })
                        .collect(Collectors.toList())
        );
        return dtoPage;
    }
}
